use std::collections::HashMap;
use std::sync::Mutex;

use crate::db::define::SYSTEM_ID;
use crate::db::entities::role::ROLE_ADMIN;
use crate::rest_api::api_user::{User, UserToken};
use anyhow::anyhow;
use anyhow::{Ok, Result};
use log::trace;
use rbase::id_utils::str2id;
use rbase::time_utils::get_systemtime_millis;
use uuid::Uuid;

pub static TOKENS: std::sync::LazyLock<Mutex<HashMap<String, UserToken>>> = std::sync::LazyLock::new(|| Mutex::new(std::collections::HashMap::new()));

pub static TIMEOUT: i64 = 1000 * 60 * 3;
pub fn create_token(user: &User) -> Result<String> {
    let token = Uuid::new_v4().to_string();
    let mut lock = TOKENS.lock().or_else(|e| Err(anyhow!("Failed to lock TOKENS: {}", e)))?;
    trace!("Creating token for user: {:?} with token: {}", user.login_name, token);
    let roles = user.roles.clone().unwrap_or(Vec::new());
    let is_admin = roles.contains(&ROLE_ADMIN.to_string());
    let id = str2id(&user.id)?;
    let owner_ids = if is_admin { None } else { Some(vec![SYSTEM_ID, id]) };
    lock.insert(
        token.clone(),
        UserToken {
            id: str2id(&user.id)?,
            timeout: get_systemtime_millis() + TIMEOUT,
            is_admin,
            roles,
            owner_ids,
        },
    );
    Ok(token)
}

pub fn get_user_token(token: String) -> Result<UserToken> {
    trace!("Getting user by token: {}", token);
    let mut lock = TOKENS.lock().or_else(|e| Err(anyhow!("Failed to lock TOKENS: {}", e)))?;
    let user_token = match lock.get_mut(&token) {
        Some(user_token) => user_token,
        None => return Err(anyhow!("Token not found")),
    };

    let systemtime = get_systemtime_millis();
    if user_token.timeout < systemtime {
        lock.remove(&token);
        return Err(anyhow!("Token expired"));
    }
    user_token.timeout = systemtime + TIMEOUT;
    Ok(user_token.clone())
}
